#pragma once

#include <math.h>

#define V3DI clkVec3<int>
#define V3DF clkVec3<float>
#define V3DZ V3DF(0,0,0)

template <typename TYPE>
struct clkVec3
{
	TYPE x, y, z;

	clkVec3()
	{x=y=z=0;}

	clkVec3(TYPE av)
	{x=y=z=av;}

	clkVec3(TYPE ax, TYPE ay, TYPE az)
	{x=ax;y=ay;z=az;}

	clkVec3(clkVec3<TYPE>& av)
	{x=av.x;y=av.y;z=av.z;}

	void operator=(TYPE av)
	{x=y=z=av;}

	void operator=(clkVec3<TYPE>& av)
	{x=av.x;y=av.y;z=av.z;}

	TYPE operator[](int av)
	{return (av==0)?x:(av==1)?y:(av==2)?z:0;}

	clkVec3<TYPE> operator-()
	{return clkVec3<TYPE>(-x,-y,-z);}

	clkVec3<TYPE> operator+(const clkVec3<TYPE>& av)
	{return clkVec3<TYPE>(x+av.x,y+av.y,z+av.z);}

	clkVec3<TYPE> operator-(const clkVec3<TYPE>& av)
	{return clkVec3<TYPE>(x-av.x,y-av.y,z-av.z);}

	clkVec3<TYPE> operator*(const clkVec3<TYPE>& av)
	{return clkVec3<TYPE>(x*av.x,y*av.y,z*av.z);}

	clkVec3<TYPE> operator/(const clkVec3<TYPE>& av)
	{return clkVec3<TYPE>((av.x!=0)?x/av.x:0,(av.y!=0)?y/av.y:0,(av.z!=0)?z/av.z:0);}

	clkVec3<TYPE> operator+(const TYPE& av)
	{return clkVec3<TYPE>(x+av,y+av,z+av);}

	clkVec3<TYPE> operator-(const TYPE& av)
	{return clkVec3<TYPE>(x-av,y-av,z-av);}

	clkVec3<TYPE> operator*(const TYPE& av)
	{return clkVec3<TYPE>(x*av,y*av,z*av);}

	clkVec3<TYPE> operator/(const TYPE& av)
	{return (av!=0)?clkVec3<TYPE>(x/av,y/av,z/av):clkVec3<TYPE>();}

	void operator+=(const clkVec3<TYPE>& av)
	{x+=av.x;y+=av.y;z+=av.z;}

	void operator-=(const clkVec3<TYPE>& av)
	{x-=av.x;y-=av.y;z-=av.z;}

	void operator*=(const clkVec3<TYPE>& av)
	{x*=av.x;y*=av.y;z*=av.z;}

	void operator/=(const clkVec3<TYPE>& av)
	{(av.x!=0)?x/=av.x:x=0;(av.y!=0)?y/=av.y:y=0;(av.z!=0)?z/=av.z:z=0;}

	void operator+=(const TYPE& av)
	{x+=av;y+=av;z+=av;}

	void operator-=(const TYPE& av)
	{x-=av;y-=av;z-=av;}

	void operator*=(const TYPE& av)
	{x*=av;y*=av;z*=av;}

	void operator/=(const TYPE& av)
	{if(av!=0){x/=av;y/=av;z/=av;}else{x=0;y=0;z=0;}}

	friend clkVec3<TYPE> operator+(const TYPE& avA, const clkVec3<TYPE>& avB)
	{return clkVec3<TYPE>(avA+avB.x,avA+avB.y,avA+avB.z);}

	friend clkVec3<TYPE> operator-(const TYPE& avA, const clkVec3<TYPE>& avB)
	{return clkVec3<TYPE>(avA-avB.x,avA-avB.y,avA-avB.z);}

	friend clkVec3<TYPE> operator*(const TYPE& avA, const clkVec3<TYPE>& avB)
	{return clkVec3<TYPE>(avA*avB.x,avA*avB.y,avA*avB.z);}

	friend clkVec3<TYPE> operator/(const TYPE& avA, const clkVec3<TYPE>& avB)
	{return (avA!=0)?clkVec3<TYPE>((avB.x!=0)?avA/avB.x:0,(avB.y!=0)?avA/avB.y:0,(avB.z!=0)?avA/avB.z:0):clkVec3<TYPE>();}

	friend clkVec3<TYPE> operator+=(const TYPE& avA, const clkVec3<TYPE>& avB)
	{return clkVec3<TYPE>(avA+avB.x,avA+avB.y,avA+avB.z);}

	friend clkVec3<TYPE> operator-=(const TYPE& avA, const clkVec3<TYPE>& avB)
	{return clkVec3<TYPE>(avA-avB.x,avA-avB.y,avA-avB.z);}

	friend clkVec3<TYPE> operator*=(const TYPE& avA, const clkVec3<TYPE>& avB)
	{return clkVec3<TYPE>(avA*avB.x,avA*avB.y,avA*avB.z);}

	friend clkVec3<TYPE> operator/=(const TYPE& avA, const clkVec3<TYPE>& avB)
	{return (avA!=0)?clkVec3<TYPE>((avB.x!=0)?avA/avB.x:0,(avB.y!=0)?avA/avB.y:0,(avB.z!=0)?avA/avB.z:0):clkVec3<TYPE>();}

	bool operator<(const clkVec3<TYPE>& av)
	{return (x<av.x&&y<av.y&&z<av.z)?true:false;}

	bool operator>(const clkVec3<TYPE>& av)
	{return (x>av.x&&y>av.y&&z>av.z)?true:false;}

	bool operator<=(const clkVec3<TYPE>& av)
	{return (x<=av.x&&y<=av.y&&z<=av.z)?true:false;}

	bool operator>=(const clkVec3<TYPE>& av)
	{return (x>=av.x&&y>=av.y&&z>=av.z)?true:false;}

	bool operator==(const clkVec3<TYPE>& av)
	{return (x==av.x&&y==av.y&&z==av.z)?true:false;}

	bool operator!=(const clkVec3<TYPE>& av)
	{return (x!=av.x&&y!=av.y&&z!=av.z)?true:false;}

	bool zeroed()
	{return x==0&&y==0&&z==0;}

	void set(TYPE av)
	{x=y=z=av;}

	void set(TYPE ax, TYPE ay, TYPE az)
	{x=ax;y=ay;z=az;}

	void set(clkVec3<TYPE> av)
	{x=av.x;y=av.y;z=av.z;}

	void zero()
	{x=y=z=0;}

	void negate()
	{x=-x;y=-y;z=-z;}

	TYPE distance(clkVec3<TYPE> av)
	{return sqrt(distanceSq(av));}

	TYPE distanceSq(clkVec3<TYPE> av)
	{TYPE dx=x-av.x,dy=y-av.y,dz=z-av.z; return (dx*dx)+(dy*dy)+(dz*dz);}

	TYPE dot(clkVec3<TYPE> av)
	{return (x*av.x)+(y*av.y)+(z*av.z);}

	TYPE magnitude()
	{return sqrt(magnitudeSq());}

	TYPE magnitudeSq()
	{return (x*x)+(y*y)+(z*z);}

	clkVec3<TYPE> cross(clkVec3<TYPE> av)
	{clkVec3<TYPE> c;c.x=y*av.z-z*av.y;c.y=z*av.x-x*av.z;c.z=x*av.y-y*av.x;return c;}

	clkVec3<TYPE> normal()
	{clkVec3<TYPE> n=*this;n.normalize();return n;}

	clkVec3<TYPE> normalize()
	{float m=magnitude();if(m!=0){if(x!=0)x/=m;if(y!=0)y/=m;if(z!=0)z/=m;}return *this;}

	clkVec3<TYPE> perp()
	{return clkVec3<TYPE>(-y,x,z);}
};